/**
 * Grain集群示例
 * 
 * 这个示例展示了如何使用ProtoActor-TS的Grain抽象
 * Grain是集群化Actor的高级抽象，提供了更简单的使用接口
 */

import { ActorSystem, Props } from '../src/actor';
import { Remote } from '../src/remote/remote';
import { Cluster, GrainBase, GrainRegistry } from '../src/cluster';
import { ClusterConfig } from '../src/cluster/clusterConfig';
import { LocalProvider } from '../src/cluster/providers/localProvider';
import { LocalIdentityLookup } from '../src/cluster/providers/localIdentityLookup';
import { PID } from '../src/actor/pid';

// 延时函数
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

// ====== 定义用户Grain接口 ======

interface IUserGrain {
  // 获取用户信息
  getUser(): Promise<User>;
  
  // 更新用户信息
  updateUser(userData: Partial<User>): Promise<void>;
  
  // 记录用户活动
  recordActivity(activity: string): Promise<void>;
}

// 用户信息类型
interface User {
  id: string;
  name: string;
  email: string;
  createdAt: number;
  lastActivity?: string;
  lastActivityTime?: number;
}

// ====== 实现用户Actor ======

// 用户Actor消息类型
type UserActorMessage = 
  | { type: 'get-user' }
  | { type: 'update-user', data: Partial<User> }
  | { type: 'record-activity', activity: string };

// 用户Actor
class UserActor {
  // 用户数据
  private userData: User | null = null;
  
  constructor(private userId: string) {
    // 初始化用户数据
    this.userData = {
      id: userId,
      name: `User ${userId}`,
      email: `user${userId}@example.com`,
      createdAt: Date.now()
    };
  }
  
  // 处理消息
  async receive(context: any): Promise<void> {
    const message = context.message as UserActorMessage;
    
    switch (message.type) {
      case 'get-user':
        await this.handleGetUser(context);
        break;
        
      case 'update-user':
        await this.handleUpdateUser(context, message.data);
        break;
        
      case 'record-activity':
        await this.handleRecordActivity(context, message.activity);
        break;
    }
  }
  
  // 处理获取用户请求
  private async handleGetUser(context: any): Promise<void> {
    await context.respond(this.userData);
  }
  
  // 处理更新用户请求
  private async handleUpdateUser(context: any, data: Partial<User>): Promise<void> {
    if (this.userData) {
      this.userData = { ...this.userData, ...data };
      await context.respond({ success: true });
    } else {
      await context.respond({ 
        success: false, 
        error: '用户不存在' 
      });
    }
  }
  
  // 处理记录活动请求
  private async handleRecordActivity(context: any, activity: string): Promise<void> {
    if (this.userData) {
      this.userData.lastActivity = activity;
      this.userData.lastActivityTime = Date.now();
      await context.respond({ success: true });
    } else {
      await context.respond({ 
        success: false, 
        error: '用户不存在' 
      });
    }
  }
}

// ====== 实现用户Grain ======

// 用户Grain实现
class UserGrain extends GrainBase implements IUserGrain {
  constructor(cluster: Cluster, userId: string) {
    super(cluster, 'user', userId);
  }
  
  // 获取用户信息
  async getUser(): Promise<User> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活UserGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    return actorSystem.root.requestAs<User>(pid, { type: 'get-user' });
  }
  
  // 更新用户信息
  async updateUser(userData: Partial<User>): Promise<void> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活UserGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    const response = await actorSystem.root.requestAs<{ success: boolean, error?: string }>(
      pid, 
      { type: 'update-user', data: userData }
    );
    
    if (!response.success) {
      throw new Error(response.error || '更新用户失败');
    }
  }
  
  // 记录用户活动
  async recordActivity(activity: string): Promise<void> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活UserGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    const response = await actorSystem.root.requestAs<{ success: boolean, error?: string }>(
      pid, 
      { type: 'record-activity', activity }
    );
    
    if (!response.success) {
      throw new Error(response.error || '记录活动失败');
    }
  }
}

// ====== 用户Grain工厂 ======

class UserGrainFactory {
  constructor(private cluster: Cluster) {}
  
  // 获取用户Grain
  get(userId: string): UserGrain {
    return new UserGrain(this.cluster, userId);
  }
}

// ====== 主函数 ======

async function main() {
  try {
    console.log('启动Grain集群示例...');
    
    // 创建Actor系统
    const system = new ActorSystem();
    
    // 配置远程通信
    const remote = new Remote(system, {
      host: 'localhost',
      port: 12001
    });
    
    // 启动远程通信系统
    await remote.start();
    console.log('远程通信系统已启动');
    
    // 创建集群配置
    const clusterConfig: ClusterConfig = {
      clusterName: 'grain-cluster',
      nodeAddress: 'localhost:12001',
      hostname: 'localhost',
      port: 12001,
      providerType: 'local',
      providerConfig: {},
      reconnectInterval: 1000,
      heartbeatInterval: 1000,
      enableVirtualNodes: false,
      virtualNodeCount: 10
    };
    
    // 创建本地集群提供者
    const provider = new LocalProvider({
      heartbeatInterval: 1000,
      simulateNetworkDelay: true,
      networkDelayRange: [10, 50]
    });
    
    // 创建本地身份查找服务
    const identityLookup = new LocalIdentityLookup({
      enableCache: true,
      cacheExpiration: 10000
    });
    
    // 创建集群
    const cluster = new Cluster(system, remote, clusterConfig, provider, identityLookup);
    
    // 初始化集群
    await cluster.init();
    console.log('集群已初始化');
    
    // 注册用户Grain
    const registry = GrainRegistry.getInstance();
    
    // 注册Grain种类
    registry.registerGrain('user', (identity) => {
      return Props.fromProducer(() => new UserActor(identity));
    });
    
    // 启动集群
    await cluster.start();
    console.log('集群已启动');
    
    // 等待集群稳定
    await delay(1000);
    
    // 创建用户Grain工厂
    const userGrainFactory = new UserGrainFactory(cluster);
    
    // 创建不同的用户Grain
    const user1 = userGrainFactory.get('1001');
    const user2 = userGrainFactory.get('1002');
    
    // 使用user1
    console.log('获取用户1信息...');
    const user1Data = await user1.getUser();
    console.log('用户1信息:', user1Data);
    
    // 更新user1信息
    console.log('更新用户1信息...');
    await user1.updateUser({
      name: '张三',
      email: 'zhangsan@example.com'
    });
    
    // 记录user1活动
    console.log('记录用户1活动...');
    await user1.recordActivity('登录系统');
    
    // 获取更新后的user1信息
    console.log('获取更新后的用户1信息...');
    const updatedUser1Data = await user1.getUser();
    console.log('更新后的用户1信息:', updatedUser1Data);
    
    // 使用user2
    console.log('获取用户2信息...');
    const user2Data = await user2.getUser();
    console.log('用户2信息:', user2Data);
    
    // 更新user2信息
    console.log('更新用户2信息...');
    await user2.updateUser({
      name: '李四',
      email: 'lisi@example.com'
    });
    
    // 记录user2活动
    console.log('记录用户2活动...');
    await user2.recordActivity('查看资料');
    
    // 获取更新后的user2信息
    console.log('获取更新后的用户2信息...');
    const updatedUser2Data = await user2.getUser();
    console.log('更新后的用户2信息:', updatedUser2Data);
    
    // 关闭Grain
    await user1.shutdown();
    await user2.shutdown();
    
    // 等待一段时间让日志输出
    await delay(1000);
    
    // 关闭集群
    console.log('关闭集群...');
    await cluster.shutdown();
    
    // 关闭远程系统
    await remote.shutdown();
    
    // 结束示例
    console.log('Grain集群示例已完成');
  } catch (error) {
    console.error('Grain集群示例出错:', error);
  }
}

// 运行主函数
main().catch(console.error); 